package earogya.ehr.medical_records.messages;

import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.hibernate.HibernateException;

import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.DataTypeException;
import ca.uhn.hl7v2.model.v251.message.ADT_A17;
import ca.uhn.hl7v2.model.v251.segment.MSH;
import ca.uhn.hl7v2.model.v251.segment.PID;
import ca.uhn.hl7v2.model.v251.segment.PV1;
import earogya.ehr.medical_records.BedExchange;
import earogya.ehr.medical_records.HibernateManager;

/***
 * The A17 is used when it is decided that two patients will exchange beds.  
 * The patient ID and visit data are repeated for the two patients changing places.  
 * @author Chamendri
 *
 */
public class ADT_17_Handler {

	private ADT_A17 adtMsg;
	private HibernateManager hibernate_manager=new HibernateManager();
	private BedExchange exchange_patient_1=new BedExchange();
	private BedExchange exchange_patient_2=new BedExchange();
	
	public ADT_17_Handler(ADT_A17 adtMsg){
		this.adtMsg=adtMsg;
	}
	
	public String manageMessage()throws DataTypeException, HL7Exception, IOException{
		String ack=null;
		try{
			PV1 pv1_1=adtMsg.getPV1();
			PV1 pv1_2=adtMsg.getPV12();
			PID pid_1=adtMsg.getPID();
			PID pid_2=adtMsg.getPID2();
			int patient1_id=Integer.parseInt(pid_1.getPatientID().getIDNumber().getValue());
			int patient2_id=Integer.parseInt(pid_2.getPatientID().getIDNumber().getValue());
			int admission_id_patient_1=this.getAdmissionId(patient1_id);
			int admission_id_patient_2=this.getAdmissionId(patient2_id);
			if(admission_id_patient_1!=-1 && admission_id_patient_2!=-1){
				if(isCorrectPatientOccupyingTheBed(pv1_1, admission_id_patient_1) && isCorrectPatientOccupyingTheBed(pv1_2, admission_id_patient_2)){
					if(this.isBothPatientsInTheSameWard(pv1_1, pv1_2)){
						exchange_patient_1.setAdmission_id(admission_id_patient_1);
						exchange_patient_1.setPatient_id(patient1_id);
						exchange_patient_2.setAdmission_id(admission_id_patient_2);
						exchange_patient_2.setPatient_id(patient2_id);
						this.setPreviousWardAndBed(pv1_1, pv1_2);
						this.exchangeBed();
						
						MSH msh=adtMsg.getMSH();
						Date exchange_date=msh.getDateTimeOfMessage().getTime().getValueAsDate();
						exchange_patient_1.setExchange_date(exchange_date);
						exchange_patient_2.setExchange_date(exchange_date);
						
						hibernate_manager.saveObject(exchange_patient_1);
						hibernate_manager.saveObject(exchange_patient_2);
						Boolean isSuccessful_1=this.updateBht(admission_id_patient_1, exchange_patient_1.getCurrent_ward(), exchange_patient_1.getCurrent_bed());
						Boolean isSuccessful_2=this.updateBht(admission_id_patient_2, exchange_patient_2.getCurrent_ward(), exchange_patient_2.getCurrent_bed());
						if(isSuccessful_1 && isSuccessful_2){
							ack=adtMsg.generateACK().encode();
						}
					}else{
						HL7Exception ex=new HL7Exception("Patient's are not in the same ward. cannot exchange beds.");
						throw ex;
					}
				}
				else{
					HL7Exception ex=new HL7Exception("Given patient does not currently occupy the given bed");
					throw ex;
				}
			}
		}catch(HL7Exception e){
			ack=adtMsg.generateACK("AE", e).encode();
		}
		return ack;
	}
	
	private int getAdmissionId(int patient_id) throws DataTypeException, HL7Exception{
		int admission_id=0;
		Object[][] fieldsAndValues={{"patient_id", patient_id},{"status", "in"}};
		admission_id=hibernate_manager.queryValuesFromDatabase(fieldsAndValues, "admission_id", "Admission", "admission");
		return admission_id;
	}
	
	private void setPreviousWardAndBed(PV1 pv1, PV1 pv2){
		int previous_ward_1=Integer.parseInt(pv1.getAssignedPatientLocation().getRoom().getValue());
		int previous_bed_1=Integer.parseInt(pv1.getAssignedPatientLocation().getBed().getValue());
		exchange_patient_1.setPrevious_ward(previous_ward_1);
		exchange_patient_1.setPrevious_bed(previous_bed_1);
		
		int previous_ward_2=Integer.parseInt(pv2.getAssignedPatientLocation().getRoom().getValue());
		int previous_bed_2=Integer.parseInt(pv2.getAssignedPatientLocation().getBed().getValue());
		exchange_patient_2.setPrevious_ward(previous_ward_2);
		exchange_patient_2.setPrevious_bed(previous_bed_2);
	}
	
	private void exchangeBed(){
		exchange_patient_2.setCurrent_ward(exchange_patient_1.getPrevious_ward());
		exchange_patient_2.setCurrent_bed(exchange_patient_1.getPrevious_bed());
		
		exchange_patient_1.setCurrent_ward(exchange_patient_2.getPrevious_ward());
		exchange_patient_1.setCurrent_bed(exchange_patient_2.getPrevious_bed());
	}
	
	private Boolean updateBht(int admission_id, int ward, int bed) throws HibernateException{
		Boolean isSucessful=false;
		Object[][] fieldsAndValues={{"admission_id", admission_id}};
		int bht_id=hibernate_manager.queryValuesFromDatabase(fieldsAndValues, "bht_id", "Bht", "bht");
		if(bht_id!=-1){
			isSucessful=hibernate_manager.updateBhtEntry(bht_id, bed, ward);
		}
		return isSucessful;
	}
	
	private Boolean isCorrectPatientOccupyingTheBed(PV1 pv1, int admission_id){
		Boolean isCorrect=false;
		int bed=Integer.parseInt(pv1.getAssignedPatientLocation().getBed().getValue());
		int ward=Integer.parseInt(pv1.getAssignedPatientLocation().getRoom().getValue());
		Object[][] fieldsAndValues={{"current_ward", ward}, {"current_bed", bed}};
		List list=hibernate_manager.queryValueListFromDatabase(fieldsAndValues, "admission_id", "Bht", "bht");
		if(list.size()==1){
			if((Integer)list.get(0)==admission_id){
				isCorrect=true;
			}
		}
		return isCorrect;
	}
	
	private Boolean isBothPatientsInTheSameWard(PV1 pv1, PV1 pv2){
		Boolean isInTheSameWard=false;
		int ward1=Integer.parseInt(pv1.getAssignedPatientLocation().getRoom().getValue());
		int ward2=Integer.parseInt(pv2.getAssignedPatientLocation().getRoom().getValue());
		if(ward1==ward2){
			isInTheSameWard=true;
		}
		return isInTheSameWard;
	}
}
